//+------------------------------------------------------------------+
//|                   ChartObject.mqh MQL5 图表对象基类头文件        |
//|                版权所有 2000-2025, MetaQuotes Ltd.              |
//|                        官方网址: https://www.mql5.com            |
//+------------------------------------------------------------------+
#include <Object.h>  // 引入 MQL5 基础对象类 CObject（提供链表节点管理能力）

//+------------------------------------------------------------------+
//| CChartObject 类                                                   |
//| 功能：MQL5 图表对象抽象基类，定义所有图表对象的统一接口与核心属性   |
//| 继承关系：public CObject（基于基础对象类，支持链表集成与遍历）     |
//| 核心特性：                                                      |
//|  1. 绑定图表与子窗口：关联对象到指定图表及子窗口（主窗口/指标窗口） |
//|  2. 锚点管理：支持多锚点对象（如趋势线、通道线）的坐标读写          |
//|  3. 通用属性控制：颜色、线型、线宽、层级（Z-Order）等可视化属性    |
//|  4. 层级（Level）支持：为带水平层级的对象（如布林带、均线）提供层级管理 |
//|  5. 交互控制：支持选中状态、可选中性等交互属性                      |
//|  6. 生命周期管理：自动销毁关联的图表对象，避免资源残留              |
//|  7. 序列化支持：支持对象参数的文件读写（保存/加载配置）              |
//| 适用场景：所有 MQL5 图表对象（趋势线、文本、箭头、通道、指标线等）均需继承此类 |
//+------------------------------------------------------------------+
class CChartObject : public CObject
  {
protected:
   long              m_chart_id;           // 图表ID（标识对象所属的图表，-1 表示未绑定图表）
   int               m_window;             // 子窗口编号（0 表示主窗口，≥1 表示指标子窗口）
   string            m_name;               // 对象唯一名称（图表内唯一，用于识别对象）
   int               m_num_points;         // 锚点数量（对象的控制点数量，如趋势线为 2 个锚点）

public:
   /**
    * @brief 构造函数：初始化图表对象
    * @details 调用父类 CObject 构造函数，通过 Detach 方法初始化核心属性（未绑定图表、无锚点）
    */
                     CChartObject(void);

   /**
    * @brief 析构函数：销毁图表对象
    * @details 若对象已绑定图表（m_chart_id ≠ -1），自动调用 ObjectDelete 删除图表上的实际对象，避免资源残留
    */
                    ~CChartObject(void);

   //--- 对象类型标识（纯虚接口，子类必须重写以返回具体对象类型）
   /**
    * @brief 获取图表对象类型（子类需重写）
    * @return int - 对象类型标识（如 OBJ_TREND 表示趋势线，OBJ_TEXT 表示文本对象）
    * @note 基类默认返回 0x8888，子类需返回 MQL5 预定义的对象类型常量（见 ENUM_OBJECT_TYPE）
    */
   virtual int       Type(void) const { return(0x8888); }

   //--- 核心属性访问接口（获取对象基础信息）
   /**
    * @brief 获取对象所属图表的 ID
    * @return long - 图表 ID（-1 表示对象未绑定图表）
    */
   long              ChartId(void) const { return(m_chart_id); }

   /**
    * @brief 获取对象所属的子窗口编号
    * @return int - 子窗口编号（0=主窗口，≥1=指标子窗口）
    */
   int               Window(void) const { return(m_window); }

   /**
    * @brief 获取对象的唯一名称
    * @return string - 对象名称（图表内唯一，不可为空）
    */
   string            Name(void) const { return(m_name); }

   /**
    * @brief 修改对象的唯一名称
    * @param name [in] 新名称（图表内必须唯一，否则修改失败）
    * @return bool - 操作结果：true 表示名称修改成功，false 表示失败（如名称已存在/未绑定图表）
    */
   bool              Name(const string name);

   /**
    * @brief 获取对象的锚点数量
    * @return int - 锚点数量（如趋势线返回 2，矩形返回 4）
    */
   int               NumPoints(void) const { return(m_num_points); }

   //--- 对象绑定与初始化接口
   /**
    * @brief 将对象绑定到指定图表与子窗口（关联已存在的图表对象）
    * @param chart_id [in] 目标图表 ID（0 表示当前图表，可通过 ChartID() 获取）
    * @param name [in] 对象名称（图表内已存在的对象名称）
    * @param window [in] 子窗口编号（0=主窗口，≥1=指标子窗口）
    * @param points [in] 锚点数量（需与图表对象实际锚点数量一致）
    * @return bool - 操作结果：true 表示绑定成功，false 表示失败（如对象不存在/参数不匹配）
    * @note 绑定后，对象的属性操作（如颜色、坐标）将直接作用于图表上的实际对象
    */
   bool              Attach(long chart_id,const string name,const int window,const int points);

   /**
    * @brief 设置指定锚点的时间与价格坐标
    * @param point [in] 锚点索引（0 开始，需 < m_num_points）
    * @param time [in] 锚点的时间坐标（K 线时间，如 D'2024.01.01'）
    * @param price [in] 锚点的价格坐标（图表价格，如 1.20000）
    * @return bool - 操作结果：true 表示设置成功，false 表示失败（如未绑定图表/锚点索引无效）
    */
   bool              SetPoint(const int point,const datetime time,const double price) const;

   //--- 对象销毁与解绑接口
   /**
    * @brief 从图表删除对象（销毁图表上的实际对象并解绑）
    * @return bool - 操作结果：true 表示删除成功，false 表示失败（如未绑定图表）
    * @note 删除后，对象的 m_chart_id 设为 -1，不可再操作图表属性
    */
   bool              Delete(void);

   /**
    * @brief 解绑对象与图表（仅重置属性，不删除图表上的实际对象）
    * @details 将 m_chart_id 设为 -1，m_window 设为 -1，m_name 设为 NULL，m_num_points 设为 0
    * @note 解绑后，对象与图表无关联，但图表上的实际对象仍存在
    */
   void              Detach(void);

   //--- 锚点坐标读写接口（时间与价格）
   /**
    * @brief 获取指定锚点的时间坐标
    * @param point [in] 锚点索引（0 开始，需 < m_num_points）
    * @return datetime - 时间坐标（0 表示获取失败，如未绑定图表/锚点索引无效）
    */
   datetime          Time(const int point) const;

   /**
    * @brief 设置指定锚点的时间坐标
    * @param point [in] 锚点索引（0 开始，需 < m_num_points）
    * @param time [in] 新的时间坐标（K 线时间）
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              Time(const int point,const datetime time) const;

   /**
    * @brief 获取指定锚点的价格坐标
    * @param point [in] 锚点索引（0 开始，需 < m_num_points）
    * @return double - 价格坐标（EMPTY_VALUE 表示获取失败）
    */
   double            Price(const int point) const;

   /**
    * @brief 设置指定锚点的价格坐标
    * @param point [in] 锚点索引（0 开始，需 < m_num_points）
    * @param price [in] 新的价格坐标（图表价格）
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              Price(const int point,const double price) const;

   //--- 通用可视化属性接口（颜色、线型、线宽等）
   /**
    * @brief 获取对象的颜色（如线条颜色、文本颜色）
    * @return color - 对象颜色（clrNONE 表示获取失败，如未绑定图表）
    */
   color             Color(void) const;

   /**
    * @brief 设置对象的颜色
    * @param new_color [in] 新颜色（如 clrRed、clrBlue，需为 MQL5 颜色常量）
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              Color(const color new_color) const;

   /**
    * @brief 获取对象的线型（仅适用于带线条的对象，如趋势线、通道）
    * @return ENUM_LINE_STYLE - 线型（WRONG_VALUE 表示获取失败，如对象无线条属性）
    * @note 线型枚举值：STYLE_SOLID（实线）、STYLE_DASH（虚线）、STYLE_DOT（点线）等
    */
   ENUM_LINE_STYLE   Style(void) const;

   /**
    * @brief 设置对象的线型（仅适用于带线条的对象）
    * @param new_style [in] 新线型（需为 ENUM_LINE_STYLE 枚举值）
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              Style(const ENUM_LINE_STYLE new_style) const;

   /**
    * @brief 获取对象的线宽（仅适用于带线条的对象）
    * @return int - 线宽（像素，-1 表示获取失败）
    * @note 线宽范围通常为 1~5，值越大线条越粗
    */
   int               Width(void) const;

   /**
    * @brief 设置对象的线宽（仅适用于带线条的对象）
    * @param new_width [in] 新线宽（像素，建议 1~5）
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              Width(const int new_width) const;

   /**
    * @brief 获取“背景绘制”标志（对象是否绘制在图表背景层，不遮挡 K 线）
    * @return bool - 标志值：true=背景绘制（在 K 线下方），false=前景绘制（在 K 线上方）
    */
   bool              Background(void) const;

   /**
    * @brief 设置“背景绘制”标志
    * @param new_back [in] 新标志值（true=背景绘制，false=前景绘制）
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              Background(const bool new_back) const;

   /**
    * @brief 获取“填充”标志（仅适用于封闭对象，如矩形、通道）
    * @return bool - 标志值：true=填充内部，false=仅绘制边框
    */
   bool              Fill(void) const;

   /**
    * @brief 设置“填充”标志（仅适用于封闭对象）
    * @param new_fill [in] 新标志值（true=填充，false=不填充）
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              Fill(const bool new_fill) const;

   /**
    * @brief 获取对象的 Z 轴层级（控制多个对象的叠加顺序）
    * @return long - Z 轴层级（值越大，对象越靠上，优先级越高）
    */
   long              Z_Order(void) const;

   /**
    * @brief 设置对象的 Z 轴层级
    * @param value [in] 新层级值（建议 0~100，值越大越优先显示）
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              Z_Order(const long value) const;

   //--- 交互属性接口（选中状态、可选中性）
   /**
    * @brief 获取对象的“选中”状态（是否在图表上被鼠标选中）
    * @return bool - 状态值：true=已选中，false=未选中
    */
   bool              Selected(void) const;

   /**
    * @brief 设置对象的“选中”状态
    * @param new_sel [in] 新状态值（true=选中，false=未选中）
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              Selected(const bool new_sel) const;

   /**
    * @brief 获取对象的“可选中”标志（是否允许鼠标点击选中）
    * @return bool - 标志值：true=可选中，false=不可选中
    */
   bool              Selectable(void) const;

   /**
    * @brief 设置对象的“可选中”标志
    * @param new_sel [in] 新标志值（true=可选中，false=不可选中）
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              Selectable(const bool new_sel) const;

   //--- 描述与提示接口（备注、 tooltip）
   /**
    * @brief 获取对象的描述文本（备注信息）
    * @return string - 描述文本（空字符串表示无描述或获取失败）
    */
   string            Description(void) const;

   /**
    * @brief 设置对象的描述文本
    * @param new_text [in] 新描述文本（支持多行，为空时自动设为空格避免异常）
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              Description(const string new_text) const;

   /**
    * @brief 获取对象的鼠标悬浮提示（tooltip）
    * @return string - tooltip 文本（空字符串表示无提示或获取失败）
    */
   string            Tooltip(void) const;

   /**
    * @brief 设置对象的鼠标悬浮提示
    * @param new_text [in] 新 tooltip 文本（为空时自动设为空格避免异常）
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              Tooltip(const string new_text) const;

   //--- 时间周期可见性接口（控制对象在哪些时间周期显示）
   /**
    * @brief 获取对象的可见时间周期掩码（位掩码，控制在哪些 K 线周期显示）
    * @return int - 时间周期掩码（如 PERIOD_CURRENT 表示仅当前周期，PERIOD_ALL 表示所有周期）
    * @note 掩码值为 ENUM_TIMEFRAMES 枚举的组合（通过位或运算）
    */
   int               Timeframes(void) const;

   /**
    * @brief 设置对象的可见时间周期掩码
    * @param timeframes [in] 新时间周期掩码（如 PERIOD_H1 | PERIOD_H4 表示在 1 小时和 4 小时周期显示）
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   virtual bool      Timeframes(const int timeframes) const;

   /**
    * @brief 获取对象的创建时间
    * @return datetime - 创建时间（0 表示获取失败，如未绑定图表）
    */
   datetime          CreateTime(void) const;

   //--- 层级（Level）管理接口（适用于带水平层级的对象，如布林带、均线）
   /**
    * @brief 获取对象的层级数量（如布林带通常有 3 个层级：上轨、中轨、下轨）
    * @return int - 层级数量（0 表示无层级或获取失败）
    */
   int               LevelsCount(void) const;

   /**
    * @brief 设置对象的层级数量
    * @param new_count [in] 新层级数量（≥0，0 表示清除所有层级）
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              LevelsCount(const int new_count) const;

   /**
    * @brief 获取指定层级的颜色
    * @param level [in] 层级索引（0 开始，需 < LevelsCount()）
    * @return color - 层级颜色（clrNONE 表示获取失败）
    */
   color             LevelColor(const int level) const;

   /**
    * @brief 设置指定层级的颜色
    * @param level [in] 层级索引（0 开始，需 < LevelsCount()）
    * @param new_color [in] 新颜色（MQL5 颜色常量）
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              LevelColor(const int level,const color new_color) const;

   /**
    * @brief 获取指定层级的线型
    * @param level [in] 层级索引（0 开始，需 < LevelsCount()）
    * @return ENUM_LINE_STYLE - 层级线型（WRONG_VALUE 表示获取失败）
    */
   ENUM_LINE_STYLE   LevelStyle(const int level) const;

   /**
    * @brief 设置指定层级的线型
    * @param level [in] 层级索引（0 开始，需 < LevelsCount()）
    * @param new_style [in] 新线型（ENUM_LINE_STYLE 枚举值）
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              LevelStyle(const int level,const ENUM_LINE_STYLE new_style) const;

   /**
    * @brief 获取指定层级的线宽
    * @param level [in] 层级索引（0 开始，需 < LevelsCount()）
    * @return int - 层级线宽（-1 表示获取失败）
    */
   int               LevelWidth(const int level) const;

   /**
    * @brief 设置指定层级的线宽
    * @param level [in] 层级索引（0 开始，需 < LevelsCount()）
    * @param new_width [in] 新线宽（像素，建议 1~5）
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              LevelWidth(const int level,const int new_width) const;

   /**
    * @brief 获取指定层级的价格值（仅适用于水平层级对象，如均线价格、布林带轨道价格）
    * @param level [in] 层级索引（0 开始，需 < LevelsCount()）
    * @return double - 层级价格值（EMPTY_VALUE 表示获取失败）
    */
   double            LevelValue(const int level) const;

   /**
    * @brief 设置指定层级的价格值（仅适用于水平层级对象）
    * @param level [in] 层级索引（0 开始，需 < LevelsCount()）
    * @param new_value [in] 新价格值（图表价格）
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              LevelValue(const int level,const double new_value) const;

   /**
    * @brief 获取指定层级的描述文本
    * @param level [in] 层级索引（0 开始，需 < LevelsCount()）
    * @return string - 层级描述（空字符串表示无描述或获取失败）
    */
   string            LevelDescription(const int level) const;

   /**
    * @brief 设置指定层级的描述文本
    * @param level [in] 层级索引（0 开始，需 < LevelsCount()）
    * @param new_text [in] 新描述文本
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              LevelDescription(const int level,const string new_text) const;

   //--- MQL5 图表对象 API 通用访问接口（直接操作对象属性，兼容所有属性类型）
   /**
    * @brief 获取对象的整数类型属性（通过属性 ID，适用于未封装的扩展属性）
    * @param prop_id [in] 属性 ID（ENUM_OBJECT_PROPERTY_INTEGER 枚举值，如 OBJPROP_COLOR、OBJPROP_STYLE）
    * @param modifier [in] 属性修饰符（用于层级类属性，如层级索引，默认 -1 表示无修饰符）
    * @return long - 属性值（0 表示获取失败，如属性 ID 无效/未绑定图表）
    */
   long              GetInteger(const ENUM_OBJECT_PROPERTY_INTEGER prop_id,const int modifier=-1) const;

   /**
    * @brief 获取对象的整数类型属性（带输出参数，便于错误检查）
    * @param prop_id [in] 属性 ID（ENUM_OBJECT_PROPERTY_INTEGER 枚举值）
    * @param modifier [in] 属性修饰符（如层级索引）
    * @param value [out] 输出属性值（成功时存储属性值，失败时未定义）
    * @return bool - 操作结果：true 表示获取成功，false 表示失败
    */
   bool              GetInteger(const ENUM_OBJECT_PROPERTY_INTEGER prop_id,const int modifier,long &value) const;

   /**
    * @brief 设置对象的整数类型属性（带修饰符）
    * @param prop_id [in] 属性 ID（ENUM_OBJECT_PROPERTY_INTEGER 枚举值）
    * @param modifier [in] 属性修饰符（如层级索引）
    * @param value [in] 新属性值
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              SetInteger(const ENUM_OBJECT_PROPERTY_INTEGER prop_id,const int modifier,const long value) const;

   /**
    * @brief 设置对象的整数类型属性（无修饰符）
    * @param prop_id [in] 属性 ID（ENUM_OBJECT_PROPERTY_INTEGER 枚举值）
    * @param value [in] 新属性值
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              SetInteger(const ENUM_OBJECT_PROPERTY_INTEGER prop_id,const long value) const;

   /**
    * @brief 获取对象的浮点类型属性（通过属性 ID）
    * @param prop_id [in] 属性 ID（ENUM_OBJECT_PROPERTY_DOUBLE 枚举值，如 OBJPROP_PRICE、OBJPROP_LEVELVALUE）
    * @param modifier [in] 属性修饰符（如层级索引，默认 -1）
    * @return double - 属性值（EMPTY_VALUE 表示获取失败）
    */
   double            GetDouble(const ENUM_OBJECT_PROPERTY_DOUBLE prop_id,const int modifier=-1) const;

   /**
    * @brief 获取对象的浮点类型属性（带输出参数）
    * @param prop_id [in] 属性 ID（ENUM_OBJECT_PROPERTY_DOUBLE 枚举值）
    * @param modifier [in] 属性修饰符（如层级索引）
    * @param value [out] 输出属性值
    * @return bool - 操作结果：true 表示获取成功，false 表示失败
    */
   bool              GetDouble(const ENUM_OBJECT_PROPERTY_DOUBLE prop_id,const int modifier,double &value) const;

   /**
    * @brief 设置对象的浮点类型属性（带修饰符）
    * @param prop_id [in] 属性 ID（ENUM_OBJECT_PROPERTY_DOUBLE 枚举值）
    * @param modifier [in] 属性修饰符（如层级索引）
    * @param value [in] 新属性值
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              SetDouble(const ENUM_OBJECT_PROPERTY_DOUBLE prop_id,const int modifier,const double value) const;

   /**
    * @brief 设置对象的浮点类型属性（无修饰符）
    * @param prop_id [in] 属性 ID（ENUM_OBJECT_PROPERTY_DOUBLE 枚举值）
    * @param value [in] 新属性值
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              SetDouble(const ENUM_OBJECT_PROPERTY_DOUBLE prop_id,const double value) const;

   /**
    * @brief 获取对象的字符串类型属性（通过属性 ID）
    * @param prop_id [in] 属性 ID（ENUM_OBJECT_PROPERTY_STRING 枚举值，如 OBJPROP_TEXT、OBJPROP_TOOLTIP）
    * @param modifier [in] 属性修饰符（如层级索引，默认 -1）
    * @return string - 属性值（空字符串表示获取失败或属性为空）
    */
   string            GetString(const ENUM_OBJECT_PROPERTY_STRING prop_id,const int modifier=-1) const;

   /**
    * @brief 获取对象的字符串类型属性（带输出参数）
    * @param prop_id [in] 属性 ID（ENUM_OBJECT_PROPERTY_STRING 枚举值）
    * @param modifier [in] 属性修饰符（如层级索引）
    * @param value [out] 输出属性值
    * @return bool - 操作结果：true 表示获取成功，false 表示失败
    */
   bool              GetString(const ENUM_OBJECT_PROPERTY_STRING prop_id,const int modifier,string &value) const;

   /**
    * @brief 设置对象的字符串类型属性（带修饰符）
    * @param prop_id [in] 属性 ID（ENUM_OBJECT_PROPERTY_STRING 枚举值）
    * @param modifier [in] 属性修饰符（如层级索引）
    * @param value [in] 新属性值
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              SetString(const ENUM_OBJECT_PROPERTY_STRING prop_id,const int modifier,const string value) const;

   /**
    * @brief 设置对象的字符串类型属性（无修饰符）
    * @param prop_id [in] 属性 ID（ENUM_OBJECT_PROPERTY_STRING 枚举值）
    * @param value [in] 新属性值
    * @return bool - 操作结果：true 表示设置成功，false 表示失败
    */
   bool              SetString(const ENUM_OBJECT_PROPERTY_STRING prop_id,const string value) const;

   //--- 对象移动接口（相对位移）
   /**
    * @brief 整体移动对象（所有锚点按相同偏移量移动）
    * @param d_time [in] 时间偏移量（秒，正数表示向右移动，负数表示向左移动）
    * @param d_price [in] 价格偏移量（正数表示向上移动，负数表示向下移动）
    * @return bool - 操作结果：true 表示所有锚点移动成功，false 表示至少一个锚点移动失败
    */
   bool              ShiftObject(const datetime d_time,const double d_price) const;

   /**
    * @brief 移动指定锚点（仅移动单个锚点，不影响其他锚点）
    * @param point [in] 锚点索引（0 开始，需 < m_num_points）
    * @param d_time [in] 时间偏移量（秒）
    * @param d_price [in] 价格偏移量
    * @return bool - 操作结果：true 表示锚点移动成功，false 表示失败
    */
   bool              ShiftPoint(const int point,const datetime d_time,const double d_price) const;

   //--- 对象序列化接口（文件读写，保存/加载配置）
   /**
    * @brief 将对象参数保存到文件（序列化）
    * @param file_handle [in] 文件句柄（需提前通过 FileOpen 打开，模式为 FILE_WRITE）
    * @return bool - 操作结果：true 表示保存成功，false 表示失败（如文件句柄无效/未绑定图表）
    * @note 保存内容：对象类型、名称、颜色、线型、锚点坐标、层级信息等所有核心属性
    */
   virtual bool      Save(const int file_handle);

   /**
    * @brief 从文件加载对象参数（反序列化）
    * @param file_handle [in] 文件句柄（需提前通过 FileOpen 打开，模式为 FILE_READ）
    * @return bool - 操作结果：true 表示加载成功，false 表示失败（如文件格式错误/未绑定图表）
    * @note 加载后，对象的属性将覆盖为文件中存储的值，需确保文件为 Save 方法生成的格式
    */
   virtual bool      Load(const int file_handle);
  };
//+------------------------------------------------------------------+